{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "9TV7IYeqifSv"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors. [Licensed under the Apache License, Version 2.0](#scrollTo=ByZjmtFgB_Y5)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "tRIJp_4m_Afz"
      },
      "outputs": [],
      "source": [
        "// #@title Licensed under the Apache License, Version 2.0 (the \"License\"); { display-mode: \"form\" }\n",
        "// Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "// you may not use this file except in compliance with the License.\n",
        "// You may obtain a copy of the License at\n",
        "//\n",
        "// https://www.apache.org/licenses/LICENSE-2.0\n",
        "//\n",
        "// Unless required by applicable law or agreed to in writing, software\n",
        "// distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "// See the License for the specific language governing permissions and\n",
        "// limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "sI1ZtrdiA4aY"
      },
      "source": [
        "\u003ctable class=\"tfo-notebook-buttons\" align=\"left\"\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://www.tensorflow.org/swift/tutorials/python_interoperability\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" /\u003eTensorFlow.org에서 보기\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ko/swift/python_interoperability.ipynb\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" /\u003e구글 코랩(Colab)에서 실행하기\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ko/swift/python_interoperability.ipynb\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" /\u003e깃허브(GitHub)에서 소스 보기\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "\u003c/table\u003e"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "-agGVYp_4GWZ"
      },
      "source": [
        "Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도 불구하고 [공식 영문 문서](https://github.com/tensorflow/swift/blob/master/docs/site/tutorials/python_interoperability.ipynb)의 내용과 일치하지 않을 수 있습니다. 이 번역에 개선할 부분이 있다면 [tensorflow/docs](https://github.com/tensorflow/docs) 깃허브 저장소로 풀 리퀘스트를 보내주시기 바랍니다. 문서 번역이나 리뷰에 참여하려면 [docs-ko@tensorflow.org](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ko)로 메일을 보내주시기 바랍니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "8sa42_NblqRE"
      },
      "source": [
        "# 파이썬 상호 호환성\n",
        "\n",
        "텐서플로를 위한 스위프트는 파이썬과 상호 호환됩니다.\n",
        "\n",
        "스위프트에서 파이썬 모듈을 임포트해서, 스위프트와 파이썬 사이의 값을 바꾸거나 파이썬 함수를 호출할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "kZRlD4utdPuX"
      },
      "outputs": [],
      "source": [
        "import Python\n",
        "print(Python.version)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "lcsgrcnc490l"
      },
      "source": [
        "## 파이썬 버전 설정"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JvvMEn2o490m"
      },
      "source": [
        "기본적으로 `import Python`를 하면, 스위프트는 시스템 라이브러리 경로에 따라 설치된 최신 버전의 파이썬을 검색합니다. \n",
        "특정한 파이썬을 설치하려면, `PYTHON_LIBRARY` 환경변수에 설치시 제공받은 `libpython` 공유 라이브러리를 설정합니다.  예를 들어: \n",
        "\n",
        "`export PYTHON_LIBRARY=\"~/anaconda3/lib/libpython3.7m.so\"`\n",
        "\n",
        "정확한 파일명은 파이썬 환경과 플랫폼마다 다를 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "jELTcaDK490n"
      },
      "source": [
        "또는 스위프트가 시스템 라이브러리 경로에서 알맞은 파이썬 버전을 찾도록 해서 `PYTHON_VERSION` 환경변수를 설정할 수 있습니다. `PYTHON_LIBRARY`가 `PYTHON_VERSION` 보다 우선한다는 점을 유의해야 합니다.\n",
        "\n",
        "또한 코드에서 `PYTHON_VERSION` 설정과 동일한 기능을 하는 `PythonLibrary.useVersion` 함수를 호출할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "7jEc0ZF8490o"
      },
      "outputs": [],
      "source": [
        "// PythonLibrary.useVersion(2)\n",
        "// PythonLibrary.useVersion(3, 7)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JEucWkEK490q"
      },
      "source": [
        "__Note: 파이썬을 임포트한 직후, 파이썬 코드를 호출하기 전에 `PythonLibrary.useVersion`을 실행해야 합니다. 이것은 파이썬 버전을 동적으로 바꾸는 데 사용될 수 없습니다.__"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Meb9Mb9P490q"
      },
      "source": [
        "[파이썬 라이브러리 로딩 과정에서 생성되는 디버그 출력](https://github.com/apple/swift/pull/20674#discussion_r235207008)을 확인하기 위해서 `PYTHON_LOADER_LOGGING=1`를 설정하세요.  "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "rU0WY_sJodio"
      },
      "source": [
        "## 기초\n",
        "\n",
        "스위프트에서 `PythonObject`는 파이썬 객체를 나타냅니다.\n",
        "모든 파이썬 API는 `PythonObject` 인스턴스를 사용하거나 반환합니다.\n",
        "\n",
        "스위프트에서 기본형(숫자 및 배열처럼)은 `PythonObject`로 전환할 수 있습니다. 몇몇 경우에 (`PythonConvertible` 인수를 받는 리터럴과 함수의 경우), 변환이 암묵적으로 일어납니다. 스위프트 값을 `PythonObject`에 명시적으로 지정하려면 `PythonObject` 이니셜라이저를 사용합니다.\n",
        "\n",
        "`PythonObject`는 숫자 연산, 인덱싱, 반복을 포함한 많은 표준 연산을 정의합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "kqXILiXhq-iM"
      },
      "outputs": [],
      "source": [
        "// 표준 스위프트 자료형을 Python으로 변환합니다.\n",
        "let pythonInt: PythonObject = 1\n",
        "let pythonFloat: PythonObject = 3.0\n",
        "let pythonString: PythonObject = \"Hello Python!\"\n",
        "let pythonRange: PythonObject = PythonObject(5..\u003c10)\n",
        "let pythonArray: PythonObject = [1, 2, 3, 4]\n",
        "let pythonDict: PythonObject = [\"foo\": [0], \"bar\": [1, 2, 3]]\n",
        "\n",
        "// 파이썬 객체에 표준 연산을 수행합니다.\n",
        "print(pythonInt + pythonFloat)\n",
        "print(pythonString[0..\u003c6])\n",
        "print(pythonRange)\n",
        "print(pythonArray[2])\n",
        "print(pythonDict[\"bar\"])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "fEAEyUExXT3I"
      },
      "outputs": [],
      "source": [
        "// 파이썬 객체를 다시 스위프트로 변환합니다.\n",
        "let int = Int(pythonInt)!\n",
        "let float = Float(pythonFloat)!\n",
        "let string = String(pythonString)!\n",
        "let range = Range\u003cInt\u003e(pythonRange)!\n",
        "let array: [Int] = Array(pythonArray)!\n",
        "let dict: [String: [Int]] = Dictionary(pythonDict)!\n",
        "\n",
        "// 표준 연산을 수행합니다.\n",
        "// 출력은 파이썬과 동일합니다!\n",
        "print(Float(int) + float)\n",
        "print(string.prefix(6))\n",
        "print(range)\n",
        "print(array[2])\n",
        "print(dict[\"bar\"]!)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "1pMewsl0VgnJ"
      },
      "source": [
        "`PythonObject`는 많은 표준 스위프트 프로토콜에 대해 적합하도록 정의합니다:\n",
        "* `Equatable`\n",
        "* `Comparable`\n",
        "* `Hashable`\n",
        "* `SignedNumeric`\n",
        "* `Strideable`\n",
        "* `MutableCollection`\n",
        "* 모든 `ExpressibleBy_Literal` 프로토콜\n",
        "\n",
        "이러한 적합성은 형안전(type-safe)하지 않다는 점에 유의해야 합니다: 호환되지 않는 `PythonObject` 인스턴스에서 프로토콜 기능을 사용하려고 할 때 충돌이 발생할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "W9bUsiOxVf_v"
      },
      "outputs": [],
      "source": [
        "let one: PythonObject = 1\n",
        "print(one == one)\n",
        "print(one \u003c one)\n",
        "print(one + one)\n",
        "\n",
        "let array: PythonObject = [1, 2, 3]\n",
        "for (i, x) in array.enumerated() {\n",
        "    print(i, x)\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "w3lmTRCWT5sS"
      },
      "source": [
        "튜플을 파이썬에서 스위프트로 변환하려면, 정확한 튜플의 길이를 알아야 합니다.\n",
        "\n",
        "다음 인스턴스 메서드 중 하나를 호출합니다:\n",
        "- `PythonObject.tuple2`\n",
        "- `PythonObject.tuple3`\n",
        "- `PythonObject.tuple4`"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "fQ0HEX89T4mW"
      },
      "outputs": [],
      "source": [
        "let pythonTuple = Python.tuple([1, 2, 3])\n",
        "print(pythonTuple, Python.len(pythonTuple))\n",
        "\n",
        "// 스위프트로 변환합니다.\n",
        "let tuple = pythonTuple.tuple3\n",
        "print(tuple)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Te7sNNx9c_am"
      },
      "source": [
        "## 파이썬 내장 객체\n",
        "\n",
        "전역 `Python` 인터페이스를 활용해 파이썬 내장 객체에 접근합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "jpcOByipc75O"
      },
      "outputs": [],
      "source": [
        "// `Python.builtins`은 모든 파이썬 내장 객체의 딕셔너리입니다.\n",
        "_ = Python.builtins\n",
        "\n",
        "// 파이썬 내장 객체를 사용합니다.\n",
        "print(Python.type(1))\n",
        "print(Python.len([1, 2, 3]))\n",
        "print(Python.sum([1, 2, 3]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "H2wwUL1tY3JX"
      },
      "source": [
        "## 파이썬 모듈 임포트\n",
        "\n",
        "`Python.import`를 사용하여 파이썬 모듈을 임포트합니다. 이것은 `Python`의 `import` 키워드처럼 동작합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "XrZee8n3Y17_"
      },
      "outputs": [],
      "source": [
        "let np = Python.import(\"numpy\")\n",
        "print(np)\n",
        "let zeros = np.ones([2, 3])\n",
        "print(zeros)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "hQvza3dUXlr0"
      },
      "source": [
        "안전하게 패키지를 가져오기 위해 예외처리 함수 `Python.attemptImport`를 사용하세요."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "QD-uQGuaXhrM"
      },
      "outputs": [],
      "source": [
        "let maybeModule = try? Python.attemptImport(\"nonexistent_module\")\n",
        "print(maybeModule)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Qej_Z6V3mZnG"
      },
      "source": [
        "## `numpy.ndarray`로 변환\n",
        "\n",
        "다음 스위프트 자료형은 `numpy.ndarray`로 변환할 수 있습니다:\n",
        "- `Array\u003cElement\u003e`\n",
        "- `ShapedArray\u003cScalar\u003e`\n",
        "- `Tensor\u003cScalar\u003e`\n",
        "\n",
        "`Numpy.ndarray`의 `dtype`이 `Element` 또는 `Scalar`의 일반 파라미터 타입과 호환되어야만 변환이 성공합니다.\n",
        "\n",
        "`Array`의 경우 `numpy.ndarray`가 1-D일 경우에만 `numpy`에서 변환이 성공합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "hPvKgZBeDQ1p"
      },
      "outputs": [],
      "source": [
        "import TensorFlow\n",
        "\n",
        "let numpyArray = np.ones([4], dtype: np.float32)\n",
        "print(\"Swift type:\", type(of: numpyArray))\n",
        "print(\"Python type:\", Python.type(numpyArray))\n",
        "print(numpyArray.shape)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "ZuDgZ5cBS3Uk"
      },
      "outputs": [],
      "source": [
        "// `numpy.ndarray`에서 스위프트 타입으로 변환하는 예제.\n",
        "let array: [Float] = Array(numpy: numpyArray)!\n",
        "let shapedArray = ShapedArray\u003cFloat\u003e(numpy: numpyArray)!\n",
        "let tensor = Tensor\u003cFloat\u003e(numpy: numpyArray)!\n",
        "\n",
        "// 스위프트 타입에서 `numpy.ndarray`으로 변환하는 예제.\n",
        "print(array.makeNumpyArray())\n",
        "print(shapedArray.makeNumpyArray())\n",
        "print(tensor.makeNumpyArray())\n",
        "\n",
        "// dtype이 다른 예제.\n",
        "let doubleArray: [Double] = Array(numpy: np.ones([3], dtype: np.float))!\n",
        "let intTensor = Tensor\u003cInt32\u003e(numpy: np.ones([2, 3], dtype: np.int32))!"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "8EQFZZ5iafwh"
      },
      "source": [
        "## 이미지 표시\n",
        "\n",
        "파이썬 노트북에서처럼 `matplotlib`를 이용해 이미지를 결과 창에 표시할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "jUzsa2cxafQV"
      },
      "outputs": [],
      "source": [
        "// 준비.\n",
        "%include \"EnableIPythonDisplay.swift\"\n",
        "IPythonDisplay.shell.enable_matplotlib(\"inline\")\n",
        "\n",
        "let np = Python.import(\"numpy\")\n",
        "let plt = Python.import(\"matplotlib.pyplot\")\n",
        "\n",
        "let time = np.arange(0, 10, 0.01)\n",
        "let amplitude = np.exp(-0.1 * time)\n",
        "let position = amplitude * np.sin(3 * time)\n",
        "\n",
        "plt.figure(figsize: [15, 10])\n",
        "\n",
        "plt.plot(time, position)\n",
        "plt.plot(time, amplitude)\n",
        "plt.plot(time, -amplitude)\n",
        "\n",
        "plt.xlabel(\"Time (s)\")\n",
        "plt.ylabel(\"Position (m)\")\n",
        "plt.title(\"Oscillations\")\n",
        "\n",
        "plt.show()"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "Python interoperability.ipynb",
      "private_outputs": true,
      "provenance": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Swift",
      "language": "swift",
      "name": "swift"
    },
    "language_info": {
      "file_extension": ".swift",
      "mimetype": "text/x-swift",
      "name": "swift",
      "version": ""
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
